package com.itstudy.rpc;

import com.itstudy.common.JSONSerializer;
import com.itstudy.common.RpcEncoder;
import com.itstudy.common.RpcRequest;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @ClassName: RpcProxy
 * @Auther: Jerry
 * @Date: 2020/8/18 23:48
 * @Desctiption: TODO
 * @Version: 1.0
 */
public class RpcProxy {


    public static <T> T createProxy(Class<?> clazz) {
        MethodProxy methodProxy = new MethodProxy(clazz);
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, methodProxy);
    }

    private static class MethodProxy implements InvocationHandler {
        private Class<?> aClass;
        public MethodProxy(Class<?> aClass) {
            this.aClass = aClass;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 如果是实现类
            if (Object.class.equals(method.getDeclaringClass())){
                return method.invoke(this, args);
            } else { // 如果是接口
                return rpcInvoker(proxy, method, args);
            }
        }

        private Object rpcInvoker(Object proxy, Method method, Object[] args) {
            // 构造协议内容
            RpcRequest rpcRequest = new RpcRequest();

            rpcRequest.setClassName(this.aClass.getName());
            rpcRequest.setMethodName(method.getName());
            rpcRequest.setParameterTypes(method.getParameterTypes());
            rpcRequest.setParameters(args);

            final RpcConsumerHandler consumerHandler = new RpcConsumerHandler();

            //1)创建连接池对象
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                //2)创建客户端的引导对象
                Bootstrap bootstrap = new Bootstrap();

                //3)配置启动引导对象
                bootstrap.group(group)
                        //设置通道为NIO
                        .channel(NioSocketChannel.class)
                        //设置请求协议为TCP
                        .option(ChannelOption.TCP_NODELAY, true)
                        //监听channel 并初始化
                        .handler(new ChannelInitializer<NioSocketChannel>() {
                            @Override
                            protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                                ChannelPipeline pipeline = nioSocketChannel.pipeline();
                                pipeline.addLast(new RpcEncoder(RpcRequest.class, new JSONSerializer()));
                                pipeline.addLast(new StringDecoder());
                                pipeline.addLast(consumerHandler);
                            }
                        });
                //4)连接服务端
                ChannelFuture future = bootstrap.connect("127.0.0.1", 8999).sync();
                future.channel().writeAndFlush(rpcRequest).sync();
                future.channel().closeFuture().sync();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                group.shutdownGracefully();
            }
            return consumerHandler.response();
        }
    }
}
